Ignore ALWAYS_ABORT_FLAG in count_is_zero fast path #106197
Closed
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Based on the assumption that always_abort usage is uncommon, change the count_is_zero() fast path to only check if GLOBAL_PANIC_COUNT is not zero, ignoring ALWAYS_ABORT_FLAG. This improves code generation for the fast path, since it no longer has to mask off the flag first.
This has a small but potentially widespread impact on code quality and size, since panicking::count_is_zero() is inlined at each Mutex lock and unlock call site.
Small test case that shows the improvement:
Code generation without this change (rustc 1.67.0-nightly (2585bce 2022-11-28) on x86_64 Linux (trimmed to just the fast path to highlight the changes):
The compiler backend is clever and optimizes the
& !ALWAYS_ABORT_FLAGcheck into ashl ..., 1to shift away the top bit in the lock fast path, but for some reason doesn't apply the same optimization in the unlock path (it emits amovabsinstruction with a large0x7fffffffffffffffimmediate to mask off the flag bit instead). In either case, omitting the flag check avoids an instruction or two in the critical path.With this change applied:
With this patch applied, the inlined
panicking()function's fast path is now a load + test reg, reg + conditional jump in both the lock and unlock path.My assumption is that use of
panic::always_abort()(#84438) is uncommon and performance is not as important in cases where it has been set; if that's not accurate, maybe this change is not a good idea, since it pessimizes the always_abort case (making it always read the thread-local panic count instead).